package com.cango.framework.base.interceptor;

import com.cango.framework.base.Constants;
import com.cango.framework.base.Constants;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.util.Map;
import java.util.Properties;

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class PaginationInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, new DefaultObjectFactory(),
                new DefaultObjectWrapperFactory());
        MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
        if (!mappedStatement.getId().endsWith("ByPage")) {
            return invocation.proceed();
        }
        /*
         * RowBounds rowBounds = (RowBounds) metaStatementHandler .getValue("delegate.rowBounds"); if (rowBounds == null
         * || rowBounds == RowBounds.DEFAULT) { return invocation.proceed(); }
         */

        Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");
        String databaseType = null;
        try {
            databaseType = configuration.getVariables().getProperty("dialect").toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (databaseType == null) {
            throw new RuntimeException("the value of the dialect property in configuration.xml is not defined : "
                    + configuration.getVariables().getProperty("dialect"));
        }

        BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
        String originalSql = boundSql.getSql();

        // 只有以”ByPage“结尾的sqlId才进行分页
        if (mappedStatement.getId().endsWith("ByPage")) {
            Object parameterObject = boundSql.getParameterObject();
            if (parameterObject instanceof Map) {
                Map map = (Map) parameterObject;
                int page = Integer.valueOf(map.get(Constants.PAGINATION_PAGE_KEY).toString());
                int pagesize = Integer.valueOf(map.get(Constants.PAGINATION_PAGESIZE_KEY).toString());
                metaStatementHandler.setValue("delegate.boundSql.sql",
                        getLimitString(originalSql, (page - 1) * pagesize, pagesize));
            } else {
                throw new RuntimeException("parameter is unavailable!");
            }

        }
        metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
        metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
        return invocation.proceed();
    }

    private String getLimitString(String originalSql, int offset, int limit) {
        return originalSql + " limit " + offset + ", " + limit;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

}
